/*
 * 
 * 
 * 
 */
package com.hboxs.asl.service.impl;

import com.hboxs.asl.*;
import com.hboxs.asl.dao.DepositDao;
import com.hboxs.asl.dao.MemberDao;
import com.hboxs.asl.entity.Admin;
import com.hboxs.asl.entity.Category;
import com.hboxs.asl.entity.Deposit;
import com.hboxs.asl.entity.Member;
import com.hboxs.asl.qcloudLVB.entity.Live;
import com.hboxs.asl.service.MemberService;
import com.hboxs.asl.util.SettingUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.persistence.LockModeType;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * Service - 会员
 */
@Service("memberServiceImpl")
public class MemberServiceImpl extends BaseServiceImpl<Member, Long> implements MemberService {

    @Resource(name = "memberDaoImpl")
    private MemberDao memberDao;
    @Resource(name = "depositDaoImpl")
    private DepositDao depositDao;

    @Resource(name = "memberDaoImpl")
    public void setBaseDao(MemberDao memberDao) {
        super.setBaseDao(memberDao);
    }

    @Transactional(readOnly = true)
    public Member findByToken(String token) {
        return memberDao.findByToken(token);
    }

    @Transactional(readOnly = true)
    public Member findByToken2(String token) {
        return memberDao.findByToken2(token);
    }

    @Override
    public Member findByClientId(String clientId) {
        return memberDao.findByClientId(clientId);
    }

    @Override
    public Member findByCode(String code) {
        return memberDao.findByCode(code);
    }

    @Transactional(readOnly = true)
    public boolean usernameExists(String username) {
        return memberDao.usernameExists(username);
    }

    @Transactional(readOnly = true)
    public boolean phoneExists(String phone) {
        return memberDao.phoneExists(phone);
    }

    @Transactional(readOnly = true)
    public boolean usernameDisabled(String username) {
        Assert.hasText(username);
        Setting setting = SettingUtils.get();
        if (setting.getDisabledUsernames() != null) {
            for (String disabledUsername : setting.getDisabledUsernames()) {
                if (StringUtils.containsIgnoreCase(username, disabledUsername)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Transactional(readOnly = true)
    public boolean emailExists(String email) {
        return memberDao.emailExists(email);
    }

    @Transactional(readOnly = true)
    public boolean emailUnique(String previousEmail, String currentEmail) {
        if (StringUtils.equalsIgnoreCase(previousEmail, currentEmail)) {
            return true;
        } else {
            return !memberDao.emailExists(currentEmail);
        }
    }

    public void save(Member member, Admin operator) {
        Assert.notNull(member);
        memberDao.persist(member);
        if (member.getBalance().compareTo(new BigDecimal(0)) > 0) {
            Deposit deposit = new Deposit();
            deposit.setType(operator != null ? Deposit.Type.adminRecharge : Deposit.Type.memberRecharge);
            deposit.setCredit(member.getBalance());
            deposit.setDebit(new BigDecimal(0));
            deposit.setBalance(member.getBalance());
            deposit.setOperator(operator != null ? operator.getUsername() : null);
            deposit.setMember(member);
            depositDao.persist(deposit);
        }
    }

    public void update(Member member, BigDecimal modifyPoint, BigDecimal modifyBalance, String depositMemo, Admin operator) {
        Assert.notNull(member);

        memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);

        if (modifyPoint != null && modifyPoint != new BigDecimal(0) && (member.getPoint().add(modifyPoint).compareTo(new BigDecimal(0)) == 1)) {
            member.setPoint(member.getPoint().add(modifyPoint));
        }

        if (modifyBalance != null && modifyBalance.compareTo(new BigDecimal(0)) != 0 && member.getBalance().add(modifyBalance).compareTo(new BigDecimal(0)) >= 0) {
            member.setBalance(member.getBalance().add(modifyBalance));
            Deposit deposit = new Deposit();
            if (modifyBalance.compareTo(new BigDecimal(0)) > 0) {
                deposit.setType(operator != null ? Deposit.Type.adminRecharge : Deposit.Type.memberRecharge);
                deposit.setCredit(modifyBalance);
                deposit.setDebit(new BigDecimal(0));
            } else {
                deposit.setType(operator != null ? Deposit.Type.adminChargeback : Deposit.Type.memberPayment);
                deposit.setCredit(new BigDecimal(0));
                deposit.setDebit(modifyBalance);
            }
            deposit.setBalance(member.getBalance());
            deposit.setOperator(operator != null ? operator.getUsername() : null);
            deposit.setMemo(depositMemo);
            deposit.setMember(member);
            depositDao.persist(deposit);
        }

        member = memberDao.merge(member);
    }

    @Transactional(readOnly = true)
    public Member findByUsername(String username) {
        return memberDao.findByUsername(username);
    }

    @Transactional(readOnly = true)
    public List<Member> findListByEmail(String email) {
        return memberDao.findListByEmail(email);
    }

    @Override
    public List<Member> findListByClientId(String clientId) {
        return memberDao.findListByClientId(clientId);
    }

    @Transactional(readOnly = true)
    public List<Object[]> findPurchaseList(Date beginDate, Date endDate, Integer count) {
        return memberDao.findPurchaseList(beginDate, endDate, count);
    }

    @Transactional(readOnly = true)
    public boolean isAuthenticated() {
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            Principal principal = (Principal) request.getSession().getAttribute(Member.PRINCIPAL_ATTRIBUTE_NAME);
            if (principal != null) {
                return true;
            }
        }
        return false;
    }

    @Transactional(readOnly = true)
    public Member getCurrent() {
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            Principal principal = (Principal) request.getSession().getAttribute(Member.PRINCIPAL_ATTRIBUTE_NAME);
            if (principal != null) {
                return memberDao.find(principal.getId());
            }
        }
        return null;
    }

    @Transactional(readOnly = true)
    public Member getCurrentByToken() {
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            String token = request.getParameter("token");
            return memberDao.findByToken2(token);
        }
        return null;
    }

    @Transactional(readOnly = true)
    public String getCurrentUsername() {
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            Principal principal = (Principal) request.getSession().getAttribute(Member.PRINCIPAL_ATTRIBUTE_NAME);
            if (principal != null) {
                return principal.getUsername();
            }
        }
        return null;
    }

    @Override
    public Page<Member> findChildrenPage(Pageable pageable, Member member) {
        pageable.getFilters().add(Filter.eq("parent", member));
        return findPage(pageable);
    }

    @Override
    public List<Member> findAllChildren(Member member) {
        List<Filter> fs = new ArrayList<>();
        fs.add(Filter.eq("parent", member));
        return findList(null, fs, null);
    }

    @Override
    public List<Member> findALLTeacher(Member.Type teacher) {
        return memberDao.findALLTeacher(teacher);
    }

    @Override
    public Page<Member> findTeacherByCategory(Pageable pageable, Category category) {
        return memberDao.findTeacherByCategory(pageable, category);
    }

    @Override
    public Page<Member> searchTeacherPage(Pageable pageable, String name) {
        return memberDao.searchTeacherPage(pageable, name);
    }

    @Override
    public Page<Member> findPageTeacher(Pageable pageable, Member member) {
        Set<Member> teacherSet = member.getFavorAnchors();
        List<Member> teacherList = new ArrayList<Member>(teacherSet);
        // 计算分页
        int total = teacherList.size(); // 总数
        int from = (pageable.getPageNumber() - 1) * pageable.getPageSize(); // 分页开始
        int to = pageable.getPageNumber() * pageable.getPageSize(); // 分页结束
        if (from > total) {
            // 超过分页数默认返回第一页
            from = 0;
            to = pageable.getPageSize();
        }
        if (to > total) {
            to = total;
        }
        List<Member> content = teacherList.subList(from, to);
        return new Page<>(content, total, pageable);
    }

    @Override
    public Page<Member> findPageFans(Pageable pageable, Member teacher) {
        Set<Member> memberSet = teacher.getFavorMembers();
        List<Member> fansList = new ArrayList<Member>(memberSet);
        // 计算分页
        int total = fansList.size(); // 总数
        int from = (pageable.getPageNumber() - 1) * pageable.getPageSize(); // 分页开始
        int to = pageable.getPageNumber() * pageable.getPageSize(); // 分页结束
        if (from > total) {
            // 超过分页数默认返回第一页
            from = 0;
            to = pageable.getPageSize();
        }
        if (to > total) {
            to = total;
        }
        List<Member> content = fansList.subList(from, to);
        return new Page<>(content, total, pageable);
    }

    @Override
    public Page<Member> findPageLive(Pageable pageable, Live live) {
        Set<Member> watchersSet = live.getWatchedMembers();
        if (watchersSet != null) {
            List<Member> teacherList = new ArrayList<Member>(watchersSet);
            // 计算分页
            int total = teacherList.size(); // 总数
            int from = (pageable.getPageNumber() - 1) * pageable.getPageSize(); // 分页开始
            int to = pageable.getPageNumber() * pageable.getPageSize(); // 分页结束
            if (from > total) {
                // 超过分页数默认返回第一页
                from = 0;
                to = pageable.getPageSize();
            }
            if (to > total) {
                to = total;
            }
            List<Member> content = teacherList.subList(from, to);
            return new Page<>(content, total, pageable);
        }
        return new Page<>();
    }

}